Clean up Xen's event-channel interface, and semantics for binding
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 8 Jul 2005 14:17:54 +0000 (14:17 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 8 Jul 2005 14:17:54 +0000 (14:17 +0000)
to VCPUs.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h
xen/common/event_channel.c
xen/include/public/dom0_ops.h
xen/include/public/event_channel.h

index 0a79ca6bcd511724a73f50bf8a0c9344e56564b1..4798f1d4ec7d086560baa1e23aae440c75a645a2 100644 (file)
@@ -1533,13 +1533,13 @@ void __init smp_intr_init(void)
        int cpu = smp_processor_id();
 
        per_cpu(resched_irq, cpu) =
-               bind_ipi_on_cpu_to_irq(cpu, RESCHEDULE_VECTOR);
+               bind_ipi_to_irq(RESCHEDULE_VECTOR);
        sprintf(resched_name[cpu], "resched%d", cpu);
        BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt,
                           SA_INTERRUPT, resched_name[cpu], NULL));
 
        per_cpu(callfunc_irq, cpu) =
-               bind_ipi_on_cpu_to_irq(cpu, CALL_FUNCTION_VECTOR);
+               bind_ipi_to_irq(CALL_FUNCTION_VECTOR);
        sprintf(callfunc_name[cpu], "callfunc%d", cpu);
        BUG_ON(request_irq(per_cpu(callfunc_irq, cpu),
                           smp_call_function_interrupt,
index dda6c112e425ba89236f6ee3e5a563304d324ead..b293eee001d189888a5115d744443780eff9bc29 100644 (file)
@@ -236,17 +236,17 @@ void unbind_virq_from_irq(int virq)
     spin_unlock(&irq_mapping_update_lock);
 }
 
-int bind_ipi_on_cpu_to_irq(int cpu, int ipi)
+int bind_ipi_on_cpu_to_irq(int ipi)
 {
     evtchn_op_t op;
     int evtchn, irq;
+    int cpu = smp_processor_id();
 
     spin_lock(&irq_mapping_update_lock);
 
     if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 )
     {
-        op.cmd                 = EVTCHNOP_bind_ipi;
-        op.u.bind_ipi.ipi_vcpu = cpu;
+        op.cmd = EVTCHNOP_bind_ipi;
         if ( HYPERVISOR_event_channel_op(&op) != 0 )
             panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu);
         evtchn = op.u.bind_ipi.port;
@@ -278,9 +278,9 @@ void rebind_evtchn_from_ipi(int cpu, int newcpu, int ipi)
 
     spin_lock(&irq_mapping_update_lock);
 
-    op.cmd          = EVTCHNOP_rebind;
-    op.u.rebind.port = evtchn;
-    op.u.rebind.vcpu = newcpu;
+    op.cmd              = EVTCHNOP_bind_vcpu;
+    op.u.bind_vcpu.port = evtchn;
+    op.u.bind_vcpu.vcpu = newcpu;
     if ( HYPERVISOR_event_channel_op(&op) != 0 )
        printk(KERN_INFO "Failed to rebind IPI%d to CPU%d\n",ipi,newcpu);
 
@@ -294,18 +294,19 @@ void rebind_evtchn_from_irq(int cpu, int newcpu, int irq)
 
     spin_lock(&irq_mapping_update_lock);
 
-    op.cmd          = EVTCHNOP_rebind;
-    op.u.rebind.port = evtchn;
-    op.u.rebind.vcpu = newcpu;
+    op.cmd              = EVTCHNOP_bind_vcpu;
+    op.u.bind_vcpu.port = evtchn;
+    op.u.bind_vcpu.vcpu = newcpu;
     if ( HYPERVISOR_event_channel_op(&op) != 0 )
        printk(KERN_INFO "Failed to rebind IRQ%d to CPU%d\n",irq,newcpu);
 
     spin_unlock(&irq_mapping_update_lock);
 }
 
-void unbind_ipi_on_cpu_from_irq(int cpu, int ipi)
+void unbind_ipi_from_irq(int ipi)
 {
     evtchn_op_t op;
+    int cpu    = smp_processor_id();
     int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
     int irq    = irq_to_evtchn[evtchn];
 
index 88c5faaf849b1338cf7767d892256f5386e8b759..af4ed763fa8862471041eb9c58fcb2d3a4624f1c 100644 (file)
 /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
 extern int  bind_virq_to_irq(int virq);
 extern void unbind_virq_from_irq(int virq);
-extern int  bind_ipi_on_cpu_to_irq(int cpu, int ipi);
-extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
+extern int  bind_ipi_to_irq(int ipi);
+extern void unbind_ipi_from_irq(int ipi);
 extern int  bind_evtchn_to_irq(int evtchn);
 extern void unbind_evtchn_from_irq(int evtchn);
 
index 8f19c41675b9f1e6f33b943857e67bb4ff0f6037..f72c14da1fbf180ed582a6c68557ba4513d02de4 100644 (file)
 /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
 extern int  bind_virq_to_irq(int virq);
 extern void unbind_virq_from_irq(int virq);
-extern int  bind_ipi_on_cpu_to_irq(int cpu, int ipi);
-extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
+extern int  bind_ipi_to_irq(int ipi);
+extern void unbind_ipi_from_irq(int ipi);
 extern int  bind_evtchn_to_irq(int evtchn);
 extern void unbind_evtchn_from_irq(int evtchn);
 
index 61ad635f5e8db99b5a89c1536f3ef73cb29b2931..13145e114dff255abb8855faaa6dd90c70a0d042 100644 (file)
@@ -220,12 +220,10 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
 
     chn1->u.interdomain.remote_dom  = d2;
     chn1->u.interdomain.remote_port = (u16)port2;
-    chn1->notify_vcpu_id            = 0;
     chn1->state                     = ECS_INTERDOMAIN;
     
     chn2->u.interdomain.remote_dom  = d1;
     chn2->u.interdomain.remote_port = (u16)port1;
-    chn2->notify_vcpu_id            = 0;
     chn2->state                     = ECS_INTERDOMAIN;
 
  out:
@@ -285,10 +283,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
 {
     struct evtchn *chn;
     struct domain *d = current->domain;
-    int            port, ipi_vcpu = bind->ipi_vcpu;
-
-    if ( (ipi_vcpu >= MAX_VIRT_CPUS) || (d->vcpu[ipi_vcpu] == NULL) )
-        return -EINVAL;
+    int            port;
 
     spin_lock(&d->evtchn_lock);
 
@@ -296,7 +291,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
     {
         chn = evtchn_from_port(d, port);
         chn->state          = ECS_IPI;
-        chn->notify_vcpu_id = ipi_vcpu;
+        chn->notify_vcpu_id = current->vcpu_id;
     }
 
     spin_unlock(&d->evtchn_lock);
@@ -326,8 +321,6 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
 
     chn = evtchn_from_port(d, port);
 
-    chn->notify_vcpu_id = 0;
-
     d->pirq_to_evtchn[pirq] = port;
     rc = pirq_guest_bind(d->vcpu[0], pirq, 
                          !!(bind->flags & BIND_PIRQ__WILL_SHARE));
@@ -441,7 +434,9 @@ static long __evtchn_close(struct domain *d1, int port1)
         BUG();
     }
 
-    chn1->state = ECS_FREE;
+    /* Reset binding to vcpu0 when the channel is freed. */
+    chn1->state          = ECS_FREE;
+    chn1->notify_vcpu_id = 0;
 
  out:
     if ( d2 != NULL )
@@ -570,26 +565,30 @@ static long evtchn_status(evtchn_status_t *status)
         status->u.virq = chn->u.virq;
         break;
     case ECS_IPI:
-        status->status     = EVTCHNSTAT_ipi;
-        status->u.ipi_vcpu = chn->notify_vcpu_id;
+        status->status = EVTCHNSTAT_ipi;
         break;
     default:
         BUG();
     }
 
+    status->vcpu = chn->notify_vcpu_id;
+
  out:
     spin_unlock(&d->evtchn_lock);
     put_domain(d);
     return rc;
 }
 
-static long evtchn_rebind(evtchn_rebind_t *bind) 
+static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind) 
 {
     struct domain *d    = current->domain;
     int            port = bind->port;
     int            vcpu = bind->vcpu;
     struct evtchn *chn;
-    long             rc = 0;
+    long           rc = 0;
+
+    if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) )
+        return -EINVAL;
 
     spin_lock(&d->evtchn_lock);
 
@@ -600,7 +599,17 @@ static long evtchn_rebind(evtchn_rebind_t *bind)
     }
 
     chn = evtchn_from_port(d, port);
-    chn->notify_vcpu_id = vcpu;
+    switch ( chn->state )
+    {
+    case ECS_UNBOUND:
+    case ECS_INTERDOMAIN:
+    case ECS_PIRQ:
+        chn->notify_vcpu_id = vcpu;
+        break;
+    default:
+        rc = -EINVAL;
+        break;
+    }
 
  out:
     spin_unlock(&d->evtchn_lock);
@@ -664,10 +673,8 @@ long do_event_channel_op(evtchn_op_t *uop)
             rc = -EFAULT;
         break;
 
-    case EVTCHNOP_rebind:
-        rc = evtchn_rebind(&op.u.rebind);
-        if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
-            rc = -EFAULT;
+    case EVTCHNOP_bind_vcpu:
+        rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
         break;
 
     default:
index 60e215b09cb367ca24908e88eb027ef700071c88..2502edd75a7621270f5284a1417e174961a669fc 100644 (file)
@@ -19,7 +19,7 @@
  * This makes sure that old versions of dom0 tools will stop working in a
  * well-defined way (rather than crashing the machine, for instance).
  */
-#define DOM0_INTERFACE_VERSION   0xAAAA100D
+#define DOM0_INTERFACE_VERSION   0xAAAA100E
 
 /************************************************************************/
 
index ceacf3fc34d4093b895847fa5232754b9de3317f..d1629ec2446c7602c60d64384797da55c8bf731f 100644 (file)
@@ -89,8 +89,6 @@ typedef struct evtchn_bind_pirq {
  */
 #define EVTCHNOP_bind_ipi         7
 typedef struct evtchn_bind_ipi {
-    /* IN parameters. */
-    u32 ipi_vcpu;
     /* OUT parameters. */
     u32 port;
 } evtchn_bind_ipi_t;
@@ -144,6 +142,7 @@ typedef struct evtchn_status {
 #define EVTCHNSTAT_virq         4  /* Channel is bound to a virtual IRQ line */
 #define EVTCHNSTAT_ipi          5  /* Channel is bound to a virtual IPI line */
     u32     status;
+    u32     vcpu;                  /* VCPU to which this channel is bound.   */
     union {
         struct {
             domid_t dom;
@@ -154,16 +153,25 @@ typedef struct evtchn_status {
         } interdomain; /* EVTCHNSTAT_interdomain */
         u32 pirq;      /* EVTCHNSTAT_pirq        */
         u32 virq;      /* EVTCHNSTAT_virq        */
-        u32 ipi_vcpu;  /* EVTCHNSTAT_ipi         */
     } u;
 } evtchn_status_t;
 
-#define EVTCHNOP_rebind        8
-typedef struct {
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ *  1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ *     the binding. This binding cannot be changed.
+ *  2. All other channels notify vcpu0 by default. This default is set when
+ *     the channel is allocated (a port that is freed and subsequently reused
+ *     has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu        8
+typedef struct evtchn_bind_vcpu {
     /* IN parameters. */
-    u32 port;                         /*  0 */
-    u32 vcpu;                         /*  4 */
-} evtchn_rebind_t; /* 8 bytes */
+    u32 port;
+    u32 vcpu;
+} evtchn_bind_vcpu_t;
 
 typedef struct evtchn_op {
     u32 cmd; /* EVTCHNOP_* */
@@ -176,7 +184,7 @@ typedef struct evtchn_op {
         evtchn_close_t            close;
         evtchn_send_t             send;
         evtchn_status_t           status;
-        evtchn_rebind_t           rebind;
+        evtchn_bind_vcpu_t        bind_vcpu;
     } u;
 } evtchn_op_t;